package com.quwan;

import com.quwan.config.yml.ImConfig;
import com.quwan.config.yml.RedisConfig;
import com.quwan.config.yml.WxpayConfig;
import com.tencentyun.TLSSigAPIv2;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.mybatis.spring.annotation.MapperScan;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Primary;

import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;


import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyStore;

@Slf4j
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan("com.quwan.mapper")
@EnableCaching
public class QuWanApplication {
    @Value("${server.http-port}")
    private Integer serverHttpPort;

    @Value("${server.https-port}")
    private Integer serverHttpsPort;

    static {
        System.setProperty("druid.mysql.usePingMethod", "false");
    }

    public static void main(String[] args) throws UnknownHostException {
        SpringApplication springApplication = new SpringApplication(QuWanApplication.class);
        ConfigurableApplicationContext applicationContext = springApplication.run(args);

        Environment env = applicationContext.getEnvironment();
        String applicationName = env.getProperty("spring.application.name");
        String port = StringUtils.hasText(env.getProperty("server.port")) ? env.getProperty("server.port") : "8080";
        String contextPath = env.getProperty("server.servlet.context-path");
        contextPath = StringUtils.hasText(contextPath) ? contextPath : "";
        String hostAddress = InetAddress.getLocalHost().getHostAddress();
        log.info("\n-----------------------------------------------------------------------------\n\t" +
                        "Application '{}' is running! Access URLs:\n\t" +
                        "Local: \t\thttp://localhost:{}{}\n\t" +
                        "External: \thttp://{}:{}{}\n\t" +
                        "APIDoc: \thttp://{}:{}{}/doc.html\n" +
                        "---------------------------------------------------------------------------",
                applicationName, port, contextPath, hostAddress, port, contextPath, hostAddress, port, contextPath);
    }

    @Primary
    @Bean
    public RestTemplate restTemplate() {
        StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        return new RestTemplateBuilder().additionalMessageConverters(m).additionalMessageConverters(new ByteArrayHttpMessageConverter()).build(RestTemplate.class);

    }

    @Bean("wxCertRestTemplate")
    public RestTemplate wxCertRestTemplate(WxpayConfig config) {
        RestTemplate restTemplate = null;
        try {
            InputStream in = new ClassPathResource(config.getCertPath()).getInputStream();
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(in, config.getMchId().toCharArray());
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, config.getMchId().toCharArray()).build();
            //{"TLSv1","TLSv1.2"} 解决jdk版本协议不兼容问题
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1", "TLSv1.2"}, null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            CloseableHttpClient httpClient = HttpClients
                    .custom()
                    .setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(5000).build())
                    .setSSLSocketFactory(sslsf)
                    .build();
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
            restTemplate = new RestTemplateBuilder().additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("utf-8"))).build(RestTemplate.class);
            restTemplate.setRequestFactory(factory);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return restTemplate;
    }


    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        // CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        return RedisCacheConfiguration.defaultCacheConfig();

    }

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson(RedisConfig redisConfig)  {
        Config config = new Config();

        config.useSingleServer()
                .setDatabase(redisConfig.getDatabase())
                .setAddress("redis://" + redisConfig.getHost() + ":" + redisConfig.getPort())
             //   .setPingConnectionInterval(10000)
                .setConnectTimeout(10000)
                .setConnectionPoolSize(64)
                .setConnectionMinimumIdleSize(24)
                .setDatabase(redisConfig.getDatabase())
                .setPassword(redisConfig.getPassword());
        return Redisson.create(config);

    }


    @Bean
    public TLSSigAPIv2 tlsSigAPIv2(ImConfig imConfig) {
        return new TLSSigAPIv2(Long.parseLong(imConfig.getAppId()), imConfig.getKey());
    }

//    @Bean
//    public MultipartConfigElement multipartConfigElement() {
//        MultipartConfigFactory factory = new MultipartConfigFactory();
//        //单个文件最大
//        factory.setMaxFileSize(DataSize.parse("100MB")); //KB,MB
//        /// 设置总上传数据总大小
//        factory.setMaxRequestSize(DataSize.parse("102400KB"));
//        return factory.createMultipartConfig();
//    }


    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint constraint = new SecurityConstraint();
                constraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("");
                constraint.addCollection(collection);
                context.addConstraint(constraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }

    @Bean
    public Connector httpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setProperty("relaxedPathChars","\"<>[\\]^`{|}");
        connector.setProperty("relaxedQueryChars","\"<>[\\]^`{|}");
        connector.setScheme("http");
        //Connector监听的http的默认端口号
        connector.setPort(serverHttpPort);
        connector.setSecure(false);
        //监听到http的端口号后转向到的https的端口号,也就是项目配置的port
        connector.setRedirectPort(serverHttpsPort);
        return connector;
    }
}
